#include "PeerListener.h"
#include "Bundle.h"
#include "XMLTree.h"
#include "Handlers.h"
#include <exception>
#include <iostream>
#include <fstream>
#include "HBSD.h"
#include <assert.h>

using namespace std;

PeerListener::PeerListener(Handlers *router) 
{
	this->router = router;
}

PeerListener::~PeerListener() 
{
	while(!msgQueue.empty())
	{
		delete(msgQueue.front());
		msgQueue.pop();
	}
	router = NULL;
}

void PeerListener::init()
{
	pthread_attr_init(&threadAttr); 
	
	// Creates a detached Thread
	pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);

	ThreadParam * tp = (ThreadParam *)malloc(sizeof(ThreadParam));
	tp->peerListener = this;	
	
	pthread_create (&thread, &threadAttr, run, (void *)tp);
	tp = NULL;
}



void PeerListener::eventDelivery(XMLTree *evtBundleDelivery, Bundle *bundle) 
{
	try 
	{
		// Make certain it is intended for the HBSD router. The endpoint name is configurable.
		XMLTree *bundleEvt = evtBundleDelivery->getChildElementRequired(string("bundle"));

		XMLTree *el;
		el = bundleEvt->getChildElementRequired(string("dest"));

		string uri = el->getAttrRequired(string("uri"));

		if (uri.compare(HBSD::hbsdRegistration) != 0) 
		{
			if (HBSD::log->enabled(Logging::DEBUG)) 
			{
				HBSD::log->debug("Ignoring router bundle not intended for HBSD: " + uri);
			}
			return;
		}

		// Note the name of the file containing the payload. Invoke
		// the thread to run asynchronously.
		PeerBundle *peerBundle = (PeerBundle *)malloc(sizeof(PeerBundle));

		peerBundle->bundle = bundle;

		el = bundleEvt->getChildElementRequired(string("payload_file"));

		peerBundle->payloadFile = el->getValue();

		msgQueue.push(peerBundle);
	} 
	catch (exception &e) 
	{
		if (HBSD::log->enabled(Logging::DEBUG)) 
		{
			HBSD::log->debug(string("Problem with delivery XML message"));
		}
		return;
	}
	
}


void *PeerListener::run(void *arg) 
{
	ThreadParam * tp =(ThreadParam*)arg;
	assert(tp->peerListener != NULL);
	
	while (true) 
	{
		PeerBundle *peerBundle = NULL;
		try 
		{
			if(tp->peerListener->msgQueue.empty())
			{
				continue;
			}
			peerBundle = tp->peerListener->msgQueue.front();
			tp->peerListener->msgQueue.pop();
			
			if (peerBundle == NULL) 
			{
				continue;
			}

			tp->peerListener->processPeerMessage(peerBundle);
		} 

		catch (exception &e) 
		{
			if (HBSD::log->enabled(Logging::ERROR)) 
			{
				HBSD::log->error(string("Unanticipated exception in PeerListener thread: ") + string(e.what()));
			}
		}
	}
	free(tp);
}
	
void PeerListener::processPeerMessage(PeerBundle *peerBundle) 
{
	ifstream dataFile;
	dataFile.open (peerBundle->payloadFile.c_str(), ios::out);

	try 
	{
		// Get the data from the file.
		string data;
		char temp[100];
		while(!dataFile.getline(temp, 100).eof())	
		{
  			data.append(temp);
		}
		dataFile.close();

		// Request that the bundle be deleted. This removes the file.
		HBSD::requester->requestDeleteBundle(peerBundle->bundle);
		// Notify the Policy Manager.
		router->policyMgr->metaDataReceived(peerBundle->bundle, (char*)data.c_str());
		
	} 

	catch (exception &e) 
	{
		// Failed to access file. Try to be helpful in isolating the
		// problem since it may be due to file or directory access
		// restrictions that are otherwise difficult to troubeleshoot.
		if (HBSD::log->enabled(Logging::ERROR)) 
		{
			HBSD::log->error(string("Unable to access bundle payload: "));
			/*if (!datFile.getParentFile().canRead()) 
			{
				HBSD::log->error(string("Verify HBSD has read access to directory \"") + datFile.getParent() + string("\""));
			} else if (datFile.exists()) 
			{
			 	HBSD::log->error(string("Verify HBSD has read access to files in directory \"") + datFile.getParent() + string("\""));
			}*/
		}
		return;
	}
}


